
package com.ifcar.app.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView.FixedViewInfo;

import java.util.ArrayList;
import java.util.List;

public class PullListView extends ListView implements OnScrollListener{
    private FrameLayout mRefreshViewContainer;

    private int mLastMotionX;

    private int mLastMotionY;

    private int mTouchSlop;
    
    private ListAdapter mListAdapter;
    
    private ArrayList<FixedViewInfo> mHeaders = new ArrayList<FixedViewInfo>();
    private ArrayList<FixedViewInfo> mFooters = new ArrayList<FixedViewInfo>();
    
    private int mScrollState = OnScrollListener.SCROLL_STATE_IDLE;
    
    private OnScrollListener mOnScrollListener;

    public PullListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    public PullListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public PullListView(Context context) {
        super(context);
        init(context);
    }

    private void init(Context context) {
        setHeaderDividersEnabled(false);
        
        mRefreshViewContainer = new FrameLayout(context);
        addHeaderView(mRefreshViewContainer, null, false);

        final ViewConfiguration configuration = ViewConfiguration.get(context);
        mTouchSlop = configuration.getScaledTouchSlop();
        setOnScrollListener(this);
    }

    public void measureRefresh(int widthMeasureSpec, int heightMeasureSpec) {
        if (mRefreshViewContainer.getLayoutParams() == null) {
            AbsListView.LayoutParams lp = new AbsListView.LayoutParams(LayoutParams.FILL_PARENT,
                    LayoutParams.WRAP_CONTENT);
            mRefreshViewContainer.setLayoutParams(lp);
        }
        measureChild(mRefreshViewContainer, widthMeasureSpec, heightMeasureSpec);
    }
    
    

    @Override
    public void addHeaderView(View v, Object data, boolean isSelectable) {
        ArrayList<FixedViewInfo> headers = new ArrayList<FixedViewInfo>();
        ArrayList<FixedViewInfo> footers = new ArrayList<FixedViewInfo>();
        headers.addAll(mHeaders);
        footers.addAll(mFooters);
        
        int len = headers.size();
        for (int i = 0; i < len; ++i) {
            FixedViewInfo info = headers.get(i);
            removeHeaderView(info.view);
        }
        
        len = footers.size();
        for (int i = 0; i < len; ++i) {
            FixedViewInfo info = footers.get(i);
            removeFooterView(info.view);
        }
        
        ListAdapter adapter = mListAdapter;
        setAdapter(null);
//        System.out.println(getAdapter());
        
        FixedViewInfo info = new FixedViewInfo();
        info.view = v;
        info.data = data;
        info.isSelectable = isSelectable;
        headers.add(info);
        
        len = headers.size();
        for (int i = 0; i < len; ++i) {
            info = headers.get(i);
            super.addHeaderView(info.view, info.data, info.isSelectable);
        }          
        mHeaders.clear();
        if (headers.size() > 0) {
            mHeaders.addAll(headers);
        }
        
        setAdapter(adapter);
        
        len = footers.size();
        for (int i = 0; i < len; ++i) {
            info = footers.get(i);
            super.addFooterView(info.view, info.data, info.isSelectable);
        } 
        mFooters.clear();
        if (footers.size() > 0) {
            mFooters.addAll(footers);
        }
        
                
    }   

    @Override
    public void addFooterView(View v, Object data, boolean isSelectable) {
        FixedViewInfo info = new FixedViewInfo();
        info.view = v;
        info.data = data;
        info.isSelectable = isSelectable;
        mFooters.add(info);
        super.addFooterView(v, data, isSelectable);
    }

    @Override
    public boolean removeFooterView(View v) {
        removeFixedViewInfo(v, mFooters);
        return super.removeFooterView(v);
    }
    
    @Override
    public boolean removeHeaderView(View v) {
        removeFixedViewInfo(v, mHeaders);
        return super.removeHeaderView(v);
    }
    
    private void removeFixedViewInfo(View v, ArrayList<FixedViewInfo> where) {
        int len = where.size();
        for (int i = 0; i < len; ++i) {
            FixedViewInfo info = where.get(i);
            if (info.view == v) {
                where.remove(i);
                break;
            }
        }
    }

    @Override
    public void setAdapter(ListAdapter adapter) {
        mListAdapter = adapter;
        super.setAdapter(adapter);
    }

    @Override
    public int getHeaderViewsCount() {
        return super.getHeaderViewsCount() - 1;
    }

    @Override
    public void setOnItemClickListener(OnItemClickListener listener) {
        if (listener != null) {
            final OnItemClickListener l = listener;
            listener = new OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
                    l.onItemClick(arg0, arg1, arg2 - 1, arg3);
                }
            };
        }
        super.setOnItemClickListener(listener);
    }

    @Override
    public void setOnItemLongClickListener(OnItemLongClickListener listener) {
        if (listener != null) {
            final OnItemLongClickListener l = listener;
            listener = new OnItemLongClickListener() {
                @Override
                public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {

                    return l.onItemLongClick(arg0, arg1, arg2 - 1, arg3);
                }
            };
        }
        super.setOnItemLongClickListener(listener);
    }

    @Override
    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
        if (listener != null) {
            final OnItemSelectedListener l = listener;
            listener = new OnItemSelectedListener() {
                @Override
                public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
                    l.onItemSelected(arg0, arg1, arg2 - 1, arg3);
                }

                @Override
                public void onNothingSelected(AdapterView<?> arg0) {
                    l.onNothingSelected(arg0);
                }
            };
        }
        super.setOnItemSelectedListener(listener);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastMotionX = (int) ev.getX();
                mLastMotionY = (int) ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                int deltaX = Math.abs((int) ev.getX() - mLastMotionX);
                int deltaY = Math.abs((int) ev.getY() - mLastMotionY);
                if (deltaX > deltaY && deltaX > mTouchSlop) {
                    return false;
                }
                break;
            default:
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        boolean ret = super.onTouchEvent(ev);

        if (ev.getAction() == MotionEvent.ACTION_MOVE
                && mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
            int deltaX = Math.abs((int) ev.getX() - mLastMotionX);
            int deltaY = Math.abs((int) ev.getY() - mLastMotionY);
            if (deltaY > mTouchSlop || deltaX > mTouchSlop) {
                mScrollState = OnScrollListener.SCROLL_STATE_TOUCH_SCROLL;
            }
        }
        return ret;
    }

    boolean hasTouchScrolled() {
        return mScrollState == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL;
    }


    public void setRefreshView(View refreshView) {
        mRefreshViewContainer.removeAllViews();
        mRefreshViewContainer.addView(refreshView);

    }

    @Override
    public void setOnScrollListener(OnScrollListener l) {
        if (l == this) {
            super.setOnScrollListener(l);
            return;
        }
        mOnScrollListener = l;
    }
    
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
            int totalItemCount) { 
        if (mOnScrollListener != null) {
            mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
        }
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        mScrollState = scrollState;   
        if (mOnScrollListener != null) {
            mOnScrollListener.onScrollStateChanged(view, scrollState);
        }
    }
}
